<template>
  <div class="upload-file">
    <el-upload
      multiple
      :action="uploadFileUrl"
      :before-upload="handleBeforeUpload"
      :file-list="fileList"
      :limit="limit"
      :on-error="handleUploadError"
      :on-exceed="handleExceed"
      :on-success="handleUploadSuccess"
      :show-file-list="true"
      :headers="headers"
      class="upload-file-uploader"
      ref="fileUpload"
    >
      <!-- 上传按钮 -->
      <el-button type="primary" style="width: 80px">选取文件</el-button>
    </el-upload>
    <!-- 上传提示 -->
    <div class="el-upload__tip" v-if="showTip">
      请上传
      <template v-if="fileSize">
        大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB的文件</b>
      </template>
      <!-- <template v-if="fileType">
        格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
      </template> -->
    </div>
    <!-- 文件列表 -->
    <transition-group
      class="upload-file-list el-upload-list el-upload-list--text"
      name="el-fade-in-linear"
      tag="ul"
    >
      <li
        :key="file.uid"
        class="el-upload-list__item ele-upload-list__item-content"
        v-for="(file, index) in fileList"
      >
        <!-- <el-link :href="`${baseUrl}${file.url}`" :underline="false" target="_blank">
          <span @click="open" class="el-icon-document"> {{ getFileName(file.name) }} </span>
        </el-link> -->
        <el-link :underline="false" target="_blank">
          <span @click="open" class="el-icon-document"> {{ getFileName(file.name) }} </span>
        </el-link>
        <div class="ele-upload-list__item-content-action">
          <el-button class="yuLanBtn" type="primary" @click="yuLan">预览</el-button>
          <el-button type="danger" @click="handleDelete(index)">删除</el-button>
        </div>
      </li>
    </transition-group>

    <!-- 预览 -->
    <el-dialog v-model="dialogVisible" title="预览" :key="nodekey">
      <!-- pdf预览 -->
      <vue-pdf-embed
        v-if="filetype === '.pdf'"
        :source="pdfSource"
        style="border: 1px solid #ddd; margin-top: 20px"
      />
      <!-- docx文件预览 -->
      <div v-if="filetype === '.docx'" ref="docxContainer" class="docx-preview"></div>
      <!-- txt文件预览 -->
      <pre v-if="filetype === '.txt'" class="txt-preview">{{ fileContent }}</pre>
      <!-- xlsx文件预览 -->
      <div v-if="filetype === '.xlsx' || filetype === '.xls'">
        <table>
          <tr v-for="(row, index) in previewData" :key="index">
            <td v-for="(cell, cellIndex) in row" :key="cellIndex">{{ cell }}</td>
          </tr>
        </table>
      </div>
      <!-- doc文件预览 -->

      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogVisible = false">关闭</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 图片线上地址预览 -->
    <div v-if="showPreview" class="preview-modal" @click.self="closePreview">
      <div class="preview-content">
        <img :src="currentImage" class="preview-image" />
        <button class="close-button" @click="closePreview">
          <svg viewBox="0 0 24 24" width="24" height="24">
            <path fill="currentColor" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
          </svg>
        </button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref,defineEmits,defineProps } from 'vue'
import VuePdfEmbed from 'vue-pdf-embed'
import { renderAsync } from 'docx-preview'
import * as XLSX from 'xlsx'
import { getToken } from '@/utils/auth'
const props = defineProps({
  modelValue: [String, Object, Array],
  // 数量限制
  limit: {
    type: Number,
    default: 5,
  },
  // 大小限制(MB)
  fileSize: {
    type: Number,
    default: 500,
  },
  // 文件类型, 例如['png', 'jpg', 'jpeg']
  fileType: {
    type: Array,
    default: () => [''],
  },
  // 是否显示提示
  isShowTip: {
    type: Boolean,
    default: true,
  },
})
let nodekey = ref(Math.random())
const { proxy } = getCurrentInstance()
const emit = defineEmits(['size'])
const number = ref(0)
const uploadList = ref([])
// const baseUrl = import.meta.env.VITE_APP_BASE_API
// const baseUrl = 'http://admin.hncxykj.com:33000/prod-api'
const baseUrl = import.meta.env.VITE_APP_BASE_API
const uploadFileUrl = ref(baseUrl + '/common/upload') // 上传文件服务器地址
const headers = ref({ Authorization: 'Bearer ' + getToken() })
const fileList = ref([])
const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize))

watch(
  () => props.modelValue,
  (val) => {
    if (val) {
      let temp = 1
      // 首先将值转为数组
      const list = Array.isArray(val) ? val : props.modelValue.split(',')
      // 然后将数组转为对象数组
      fileList.value = list.map((item) => {
        if (typeof item === 'string') {
          item = { name: baseUrl + item, url: baseUrl + item }
        }
        item.uid = item.uid || new Date().getTime() + temp++
        return item
      })
    } else {
      fileList.value = []
      return []
    }
  },
  {
    deep: true,
    immediate: true,
  },
)

const pdfSource = ref('') //pdf
const docxContainer = ref(null) //docx
const fileContent = ref('') //txt
const previewData = ref(null) //xlsx
const previewUrl = ref('') //doc
let photoUrl = ref('')  //jpg
let pdfUrl = ref('')   

let filetype = ref('') //判断文件上传类型
const dialogVisible = ref(false)
const open = async () => {
  nodekey.value = Math.random()
  dialogVisible.value = true

  if (filetype.value == '.docx') {
    const reader = new FileReader() //预览docx文件
    reader.onload = (e) => {
      renderAsync(e.target.result, docxContainer.value).catch((error) =>
        console.error('DOCX渲染失败:', error),
      )
    }
    reader.readAsArrayBuffer(readerFile.value)
  }

  if (filetype.value == '.xlsx' || '.xls') {
    //预览xlsx,xls文件
    const reader = new FileReader()
    reader.onload = (e) => {
      const data = new Uint8Array(e.target.result)
      const workbook = XLSX.read(data, { type: 'array' })
      const firstSheetName = workbook.SheetNames[0]
      const worksheet = workbook.Sheets[firstSheetName]
      previewData.value = XLSX.utils.sheet_to_json(worksheet, { header: 1 }) // header: 1 表示第一行作为表头
    }
    reader.readAsArrayBuffer(readerFile.value)
  }
}

let readerFile = ref(null) //上传文件之前事件中获取的文件信息
let txtUrl = ref(null)
// 上传前校检格式和大小
const handleBeforeUpload = (file) => {
   emit('size',file.size)
  //获取各类文件的类型
  var indexs = file.name.lastIndexOf('.') // 用于返回指定字符串在当前字符串中最后一次出现的位置。
  filetype.value = file.name.slice(indexs) // 目的用来截取.jpg等字段
  readerFile.value = file

  const reader = new FileReader()
  reader.onload = (e) => {
    txtUrl.value = e.target.result // 直接读取文本内容
  }
  reader.readAsText(file, 'UTF-8') // 指定编码（UTF-8）

  // 校检文件类型
  // if (props.fileType.length) {
  //   const fileName = file.name.split('.')
  //   const fileExt = fileName[fileName.length - 1]
  //   const isTypeOk = props.fileType.indexOf(fileExt) >= 0
  //   if (!isTypeOk) {
  //     proxy.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join('/')}格式文件!`)
  //     return false
  //   }
  // }
  // 校检文件大小
  if (props.fileSize) {
    const isLt = file.size / 1024 / 1024 < props.fileSize
    if (!isLt) {
      proxy.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`)
      return false
    }
  }
  proxy.$modal.loading('正在上传文件，请稍候...')
  number.value++
  return true
}

// 文件个数超出
const handleExceed = () => {
  proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`)
}

// 上传失败
const handleUploadError = (err) => {
  proxy.$modal.msgError('上传文件失败')
}

//预览
const yuLan = () => {
  nodekey.value = Math.random()
  if (filetype.value == '.docx') {
    dialogVisible.value = true
    const reader = new FileReader() //预览docx文件
    reader.onload = (e) => {
      renderAsync(e.target.result, docxContainer.value).catch((error) =>
        console.error('DOCX渲染失败:', error),
      )
    }
    reader.readAsArrayBuffer(readerFile.value)
  }

  if (['.xlsx', '.xls'].includes(filetype.value)) {
    //预览xlsx,xls文件
    dialogVisible.value = true
    const reader = new FileReader()
    reader.onload = (e) => {
      const data = new Uint8Array(e.target.result)
      const workbook = XLSX.read(data, { type: 'array' })
      const firstSheetName = workbook.SheetNames[0]
      const worksheet = workbook.Sheets[firstSheetName]
      previewData.value = XLSX.utils.sheet_to_json(worksheet, { header: 1 }) // header: 1 表示第一行作为表头
    }
    reader.readAsArrayBuffer(readerFile.value)
  }
    
  //预览图片
   if (['.png', '.jpg', '.jpeg'].includes(filetype.value)) {
       showPreview.value = true;
       currentImage.value = photoUrl.value;
       document.body.style.overflow = 'hidden'; // 防止背景滚动
  }
  //预览pdf
  if(filetype.value==='.pdf'){
      dialogVisible.value = true
      pdfSource.value = pdfUrl.value
  }
  //预览txt
  if(filetype.value==='.txt'){
      dialogVisible.value = true
      fileContent.value = txtUrl.value
  }
}

// 上传成功回调
const handleUploadSuccess = async (res, file) => {
  if (filetype.value==='.pdf') {
    pdfUrl.value = URL.createObjectURL(file.raw)  
  }
  if(['.png', '.jpg', '.jpeg'].includes(filetype.value)){
      photoUrl.value = res.url
  }

  if (res.code === 200) {
    uploadList.value.push({ name: res.fileName, url: res.fileName })
    uploadedSuccessfully()
  } else {
    number.value--
    proxy.$modal.closeLoading()
    proxy.$modal.msgError(res.msg)
    proxy.$refs.fileUpload.handleRemove(file)
    uploadedSuccessfully()
  }
}

// 删除文件
function handleDelete(index) {
  fileList.value.splice(index, 1)
  emit('update:modelValue', listToUrl(fileList.value))
}

// 上传结束处理
function uploadedSuccessfully() {
  if (number.value > 0 && uploadList.value.length === number.value) {
    fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value)
    uploadList.value = []
    number.value = 0
    emit('update:modelValue', listToUrl(fileList.value))
    proxy.$modal.closeLoading()
  }
}

// 获取文件名称
function getFileName(name) {
  // 如果是url那么取最后的名字 如果不是直接返回
  if (name.lastIndexOf('/') > -1) {
    return name.slice(name.lastIndexOf('/') + 1)
  } else {
    return name
  }
}

// 对象转成指定字符串分隔
function listToString(list, separator) {
  let strs = ''
  separator = separator || ','
  for (let i in list) {
    if (list[i].url) {
      strs += list[i].url + separator
    }
  }
  return strs != '' ? strs.slice(0, strs.length - 1) : ''
}
// 路径拼接
function listToUrl(list) {
  list.forEach((v) => {
    if (undefined !== v) {
      v.url = baseUrl + v.url
    }
  })
  return { ...list[0] }.url
}

//图片预览
const showPreview = ref(false);
const currentImage = ref('');
// 关闭预览
const closePreview = () => {
  showPreview.value = false;
  document.body.style.overflow = '';
};
// 点击ESC键关闭预览
const handleKeyDown = (e) => {
  if (e.key === 'Escape' && showPreview.value) {
    closePreview();
  }
};
// 添加键盘事件监听
window.addEventListener('keydown', handleKeyDown);
</script>

<style scoped lang="scss">
.upload-file-uploader {
  margin-bottom: 5px;
}

.upload-file-list .el-upload-list__item {
  border: 1px solid #e4e7ed;
  line-height: 2;
  margin-bottom: 10px;
  position: relative;
}

.upload-file-list .ele-upload-list__item-content {
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: inherit;
}

// .ele-upload-list__item-content-action .el-link {
//   margin-right: 10px;
// }
.ele-upload-list__item-content-action {
  display: flex;
}
.upload-file {
  width: 500px;
}
.el-icon-document {
  width: 500px;
  white-space: nowrap; /* 禁止换行 */
  overflow: hidden; /* 隐藏溢出内容 */
  text-overflow: ellipsis; /* 显示省略号 */
  /* 可选：添加悬停效果 */
  &:hover {
    white-space: normal;
    overflow: visible;
  }
}
.yuLanBtn {
  margin-left: 10px;
}
.docx-preview {
  overflow: auto;
  border: 1px solid #eee;
}
:deep(.docx-wrapper) {
  padding: 0;
  background: #fff;
}
table {
  width: 100%;
  border-collapse: collapse;
}
table,
th,
td {
  border: 1px solid black;
}
th,
td {
  padding: 8px;
  text-align: left;
}

/* 图片预览样式 */
.preview-modal {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.8);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 9999;
}

.preview-content {
  position: relative;
  max-width: 90%;
  max-height: 90%;
}

.preview-image {
  max-width: 100%;
  max-height: 90vh;
  object-fit: contain;
  border-radius: 4px;
}

.close-button {
  position: absolute;
  top: -40px;
  right: -40px;
  background: none;
  border: none;
  color: white;
  cursor: pointer;
  font-size: 24px;
  padding: 10px;
  transition: transform 0.2s;
}

.close-button:hover {
  transform: scale(1.2);
}

@media (max-width: 768px) {
  .close-button {
    top: -50px;
    right: 10px;
  }
}
</style>
